/*
 * exprshell.cc
 *
 *  Created on: Apr 25, 2011
 *      Author: Fuxi.Zhang
 */
#include "exprshell.h"

#include <iostream>
#include <sstream>

#include <stdlib.h>

#include "utils.h"

const string usageString("Usage: exprshell [OPTION]... ");
const string helloString("Welcome ExprShell: ");
const string promptString(">>> ");
const string ctxErrString("Create context error!");

void ExprShell::PrintUsage(string args)
{
  cout << usageString << endl;
}

void ExprShell::Exit(string args)
{
  sc_release_context(ctx);
  cout << "Goodbye!" << endl;
  exit(0);  
}

void ExprShell::ListReaders(string args)
{
  sc_ctx_detect_readers(ctx);
  if (sc_ctx_get_reader_count(ctx) == 0) {
    cout << "No reader available." <<endl;
    return;
  }

  for (int i=0; i<sc_ctx_get_reader_count(ctx); i++) {
    cout << "Slot " << i << " : ";
    cout << sc_ctx_get_reader(ctx, i)->name << endl;
  }
}

void ExprShell::ConnectCard(string args)
{
  string s;
  istringstream ist(args);
  
  ist >> s;
  int slot = atoi(s.c_str());

  if ((slot == -1) || (slot >= sc_ctx_get_reader_count(ctx))) {
    cout << "Invalid slot id. Slot id must range from 0 to " ;
    cout << sc_ctx_get_reader_count(ctx) << endl;
  } else {
    sc_reader_t *reader = sc_ctx_get_reader(ctx, slot);
    sc_card_t *card = NULL;
    int r = sc_connect_card(reader, slot, &card);
    if (r < 0) {
      cout << "Failed to connect to card: " << sc_strerror(r) << endl;
    } else {
      cout << "Success to connect card in " << reader->name << endl;
      cout << "ATR : ";
      cout << Utils::convHexToString(card->atr, card->atr_len) << endl;
    }
  }
}

typedef void (ExprShell::* hdl)(string args);
int ExprShell::Main(int argc, char *argv[])
{
  const struct {
    string cmd_name;
    hdl cmd_handler;
  } cmd_disp[] = {
    {"help",     &ExprShell::PrintUsage},
    {"",         &ExprShell::Exit},
    {"exit",     &ExprShell::Exit},
    {"readers",  &ExprShell::ListReaders},
    {"connect",  &ExprShell::ConnectCard},
  };


  if (argc > 1) {
    PrintUsage("");
    return 1;
  }

  cout << helloString << endl;
  int ret = sc_context_create(&ctx, NULL);
  if (ret != SC_SUCCESS) {
    cout << ctxErrString << endl;
    exit(1);
  }

  string cmdString, cmdName;
  int i;
  while (1) {
    cout << promptString;
    getline(cin, cmdString);

    istringstream ist(cmdString);
    ist >> cmdName;
    // empty string
    if (cmdName.empty()) continue;

    for (i=0; i<sizeof(cmd_disp)/sizeof(cmd_disp[0]); i++) {
      if (cmd_disp[i].cmd_name == cmdName) {
        (this->*(cmd_disp[i].cmd_handler))(ist.str());
        break;
      }
    }

    if (i == sizeof(cmd_disp)/sizeof(cmd_disp[0])) {
      cout << "Unknown command: " << cmdString  << endl;
      PrintUsage("");
    }
  }

  // should never reached here
  return 0;
}
